package linz

class LazyFinal {

    //延迟初始化，但是用到必须初始化，否则异常
    lateinit var initParams: String

    fun init() {
        initParams = "初始化成功"
    }

    fun showResponseResult() {
        /**
         * kotlin.UninitializedPropertyAccessException: lateinit property initParams has not been initialized
         */
//        if (initParams == null) println() // 这个会抛异常，如果没有初始化

        if (::initParams.isInitialized) {
            println("param: $initParams")
        } else {
            println("没有初始化 initParams 参数")
        }
    }
}

class LazyInit {


    val dataBase = readSqlDatabaseAction()

    val dataBaseByLazy by lazy { readSqlDatabaseAction() }

    private fun readSqlDatabaseAction(): String {
        println("read....")
        println("read........")
        println("read............")
        return "read Success"
    }
}

class InitErr3(_info: String) {
    // todo getInfoValue() 初始化时间先于 info，Kotlin 是按照顺序初始化
    val content: String = getInfoValue()
    private val info = _info
    private fun getInfoValue() = info
}

class InitErr2 {
    private val info: String

    init {
        getInfoValue()
        info = "init Information"
    }

    fun getInfoValue() {
        // Exception in thread "main" java.lang.NullPointerException
        println("info:${info[0]}")
    }
}


//----------------object ----------------
interface A {
    fun funFromA() {}
}
interface B

class C {
    // The return type is Any. x is not accessible
    fun getObject() = object {
        val x: String = "x"
    }

    // The return type is A; x is not accessible
    fun getObjectA() = object: A {
        override fun funFromA() {}
        val x: String = "x"
    }

    // The return type is B; funFromA() and x are not accessible
    fun getObjectB(): B = object: A, B { // explicit return type is required
        override fun funFromA() {}
        val x: String = "x"
    }
}
//----------------object ----------------



fun main() {


    // todo 1. lateinit
    val keyword = LazyFinal()
    keyword.init()
    keyword.showResponseResult()

    // todo 2. lazy 惰性加载
//    val lazyInit = LazyInit()
//    Thread.sleep(3000)
//    println(lazyInit.dataBase)
//
//    //惰性加载
//    println(lazyInit.dataBaseByLazy)

    // todo 3 初始化陷阱

//    InitErr2()
//    println("内容长度: ${InitErr3("Information").content.length}") // java.lang.NullPointerException

    // todo 4 Kt所有的类默认final 不开放继承
    Jeep("悍马").myPrintln()

    // todo object 关键字 声明单例
    Singleton.show()

    // todo companion 伴生对象
    println(CompanionObj.info)
    println(CompanionObj.showInfo())

    // todo 数据类 copy 解构 toString hashCode
    // 普通类比较，是由Any实现的 equal的 是引用的比较
    println(Boss2("boss", 50) == Boss2("boss", 50)) // false
    // 数据类是不是有Any实现，是数值的比较
    println(Boss("boss", 50) == Boss("boss", 50))

    /**
     *  数据类 copy toString hashCode equal 只管主构造，不管次构造
     */
    val boss = Boss("boss", 32, 10)
    println(boss.copy())
    // 数据类的解构
    val (bossName,_) = boss
    println("bossName:$bossName")


    // todo 中缀表达式 infix
    mapOf("hao".to(0))
    //中缀表达式
    mapOf("good" to 0 )

    1 go "哈哈"

    //------------- :: -------------------
    fun length(s: String) = s.length

    val oddLength = compose(::isOdd, ::length)
    val strings = listOf("a", "ab", "abc")

    println(strings.filter(oddLength))

    val p = ::y.get();
    // lateinit 是否初始化
    val isInitialized = ::latest.isInitialized
    //------------- :: -------------------


}



//<fold >

@Volatile
private lateinit var latest: String
var y = 1;
fun isOdd(x: Int) = x % 2 != 0

fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C {
    return { x -> f(g(x)) }
}

//</fold >




class Boss2(val name: String,val age:Int)

data class Boss(val name: String,val age:Int){
    var level:Int = 99;
    constructor(name: String, age: Int, l: Int) : this(name,age) {
        level = l
    }
}

/**
 * 伴生对象类似于java static 对象，只初始化一次
 */
class CompanionObj {
    companion object{
        val info = "info companion"
        fun showInfo() = println("显示：$info")
    }
}

object Singleton {
    init {
        println("init ")
    }

    fun show() = println("我是show函数...")

}


open class Car(val name: String) {
    protected fun showName() = "车的名字是${name}"

    // KT 所有函数，默认为final， 不能被重新
    open fun myPrintln() = println(showName())
}

class Jeep(private val subname: String) : Car(subname) {

    override fun myPrintln() {
        println("Jeep :${showName()}")
    }
}


//** 自定义中缀表达式
private infix fun <Key, Value>  Key.go(value:Value){
    println("Key ${this}, value ${value}  ")
}

/**
 * https://stackoverflow.com/questions/45949584/how-does-the-reified-keyword-in-kotlin-work
 */
//reified
//before reified
//fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
//    val mapper = jacksonObjectMapper()
//    return mapper.readValue(this, c.java)
//}

//
//inline fun <reified T: Any> String.toKotlinObject(): T {
//    val mapper = jacksonObjectMapper()
//    return mapper.readValue(this, T::class.java)
//}

//json.toKotlinObject<MyJsonType>()







